/*
 * Animatable.cpp
 *
 *  Created on: 2009/01/25
 *      Author: Yongshik Cho
 */

#include "Animatable.h"
#include "../core/Rect2D.h"
#include "../Exception.h"
#include "../event/TickEvent.h"


AnimationFrame::AnimationFrame(const uint32 time, const Rect2D& rect)
{
	mTime = time;
	mRect = new Rect2D(rect);
	if(!mRect)
		AltoThrow(Exception::ERR_MEMORY);
}

AnimationFrame::AnimationFrame(const AnimationFrame& rhs)
{
	mTime = rhs.mTime;
	mRect = new Rect2D(*rhs.mRect);
	if(!mRect)
		AltoThrow(Exception::ERR_MEMORY);
}

AnimationFrame::~AnimationFrame()
{
	SAFE_DELETE(mRect);
}

const bool AnimationFrame::operator == (const AnimationFrame& rhs) const
{
	return (mTime == rhs.mTime && *mRect == *rhs.mRect);
}

const bool AnimationFrame::operator != (const AnimationFrame& rhs) const
{
	return !(mTime == rhs.mTime && *mRect == *rhs.mRect);
}

Animatable::Animatable()
{
	// TODO Auto-generated constructor stub
	mIndex = 0;
	mTickable = 0;
	mLoopCount = 0;
	mLoopType = ENDLESS;
}

Animatable::~Animatable()
{
	// TODO Auto-generated destructor stub
	SAFE_DELETE(mTickable);
	mFrames.clear();
}

void Animatable::addFrame(const AnimationFrame& frame)
{
	mFrames.push_back(frame);
}

void Animatable::subFrame(const AnimationFrame* frame)
{
	for(vector<AnimationFrame>::iterator it=mFrames.begin();it!=mFrames.end();)
	{
		AnimationFrame* f = &(*it);
		if(f == frame)
		{
			mFrames.erase(it);
			break;
		}
		else ++it;
	}
}

void Animatable::onTick(const Event& e)
{
	if(mLoopType != ENDLESS && !mLoopCount)
		return;

	TickEvent* _e = (TickEvent*)&e;

	AnimationFrame* frame = getFrame();
	if(_e->getTickTime() >= frame->getTime())
	{
		getNextFrame(_e->getTickTime());
		mTickable->reset();
	}
}

void Animatable::animate()
{
	mTickable = new Tickable();
	if(!mTickable)
		AltoThrow(Exception::ERR_MEMORY);

	mTickable->addEventListener(TickEvent::ON_TICK, this, &Animatable::onTick);

	dispatch(AnimationEvent(AnimationEvent::ON_START, mTickable->mLastTime));
}

const bool Animatable::operator == (Animatable& rhs)
{
	if(mLoopType != rhs.mLoopType || mLoopCount != rhs.mLoopCount)
		return false;

	if(mFrames.size() != rhs.mFrames.size())
		return false;

	for(uint32 i=0;i<mFrames.size();++i)
	{
		if(*getFrame(i) != *rhs.getFrame(i))
			return false;
	}

	return true;
}

const bool Animatable::operator != (Animatable& rhs)
{
	if(mLoopType != rhs.mLoopType || mLoopCount != rhs.mLoopCount)
		return true;

	if(mFrames.size() != rhs.mFrames.size())
		return true;

	for(uint32 i=0;i<mFrames.size();++i)
	{
		if(*getFrame(i) != *rhs.getFrame(i))
			return true;
	}

	return false;
}

AnimationFrame* Animatable::getNextFrame(const uint32 time)
{
	if(!mFrames.size())
		return 0;

	switch(mLoopType)
	{
	case LOOP_COUNT:
		if(mIndex >= (mFrames.size()-1))
		{
			if(mLoopCount > 0)
			{
				mLoopCount --;
				mIndex = 0;

				dispatch(AnimationEvent(AnimationEvent::ON_REPEAT, time));
			}
			else
			{
				dispatch(AnimationEvent(AnimationEvent::ON_END, time));
			}
		}
		else
			mIndex ++;

		break;
	case ENDLESS:
		if(mIndex >= (mFrames.size()-1))
		{
			mIndex = 0;
			dispatch(AnimationEvent(AnimationEvent::ON_REPEAT, time));
		}
		else
			mIndex ++;

		break;
	}

	return &mFrames[mIndex];
}
